home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d939.lha / ExtraCmds / source_etc.lha / src / Concat.c < prev    next >
C/C++ Source or Header  |  1993-10-22  |  10KB  |  407 lines

  1. /*   ---------------------------------      -------
  2.  *   |\  | | | | |  |.| |   \|  |/ /|\      |||||||
  3.  *   | | | |/  | |\ |/  |/|  |\ |/  |    ?  ---+---  =<
  4.  *   | | | |   | |  |     |  |  |   |     \qqqqqqqqq/
  5.  *   ---------------------------------  ~~~~~~~~~~~~~~~~
  6.  *  Concat - Concatenate and print files. AmigaDOS equivalent of UNIX cat.
  7.  *  Copyright (C) 1992, 1993 Torsten Poulin
  8.  *
  9.  *  This program is free software; you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public License as published by
  11.  *  the Free Software Foundation; either version 2 of the License, or
  12.  *  (at your option) any later version.
  13.  *
  14.  *  This program is distributed in the hope that it will be useful,
  15.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *  GNU General Public License for more details.
  18.  *
  19.  *  You should have received a copy of the GNU General Public License
  20.  *  along with this program; if not, write to the Free Software
  21.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  *
  23.  *  The author can be contacted by s-mail at
  24.  *    Torsten Poulin
  25.  *    Banebrinken 99, 2, 77
  26.  *    DK-2400 Copenhagen NV
  27.  *    DENMARK
  28.  *
  29.  * $Id: Concat.c,v 37.12 93/03/30 12:58:19 Torsten Rel $
  30.  * $Log:    Concat.c,v $
  31.  * Revision 37.12  93/03/30  12:58:19  Torsten
  32.  * Added explicit check for read errors to fastcat().
  33.  * 
  34.  * Revision 37.11  93/03/26  11:11:53  Torsten
  35.  * Now uses another copying algorithm if the VISIBLE switch is not
  36.  * specified and the destination is not a virtual terminal.
  37.  * An ad hoc test showed a twentyfold speed increase.
  38.  * Removed the QUIET switch as it wasn't used anyway ;-).
  39.  * 
  40.  * Revision 37.10  93/03/01  12:40:46  Torsten
  41.  * Changed all occurrences of "struct DosBase *" to "struct DosLibrary *"
  42.  * 
  43.  * Revision 37.9  93/02/24  00:21:33  Torsten
  44.  * Bug fix: called FreeArgs() too soon.
  45.  * 
  46.  * Revision 37.8  93/02/23  22:40:36  Torsten
  47.  * Now it only stores filenames in a list if the sort switch is given.
  48.  * The entrypoint function has been restructured a bit to get rid of
  49.  * the gotos.
  50.  * 
  51.  * Revision 37.7  93/02/22  18:15:42  Torsten
  52.  * Changed to be linked with the support library
  53.  * 
  54.  * Revision 37.6  93/02/19  18:00:14  Torsten
  55.  * Rewritten almost from scratch.
  56.  * UNBUF switch removed.
  57.  * 
  58.  * Revision 37.5  93/02/18  15:24:25  Torsten
  59.  * Removed explicit utility.library/Stricmp() pragma and prototype.
  60.  * Replaced AllocMem()/FreeMem() pair with AllocVec()/FreeVec().
  61.  * 
  62.  * Revision 37.4  93/02/11  22:47:48  Torsten
  63.  * Source reformatted with GNU indent.
  64.  * exec.library/SetSignal() replaced by dos.library/CheckSignal().
  65.  * 
  66.  * Revision 37.3  93/02/07  11:41:37  Torsten
  67.  * Updated the copyright tag.
  68.  *
  69.  * Revision 37.2  93/02/05  11:36:10  Torsten
  70.  * checked in with -k by Torsten at 93.02.05.11.36.10.
  71.  *
  72.  */
  73.  
  74. #include <exec/types.h>
  75. #include <exec/memory.h>
  76. #include <exec/lists.h>
  77. #include <exec/nodes.h>
  78. #include <dos/dos.h>
  79. #include <dos/dosasl.h>
  80. #include <clib/dos_protos.h>
  81. #include <clib/exec_protos.h>
  82. #include <clib/utility_protos.h>
  83. #ifdef __SASC
  84. #include <pragmas/dos_pragmas.h>
  85. #include <pragmas/exec_pragmas.h>
  86. #include <pragmas/utility_pragmas.h>
  87. #endif
  88. #include <string.h>
  89. #include "tastlib.h"
  90. #include "concat_rev.h"
  91.  
  92.  
  93. #define PROGNAME "Concat"
  94. #define TEMPLATE "FILE=FROM/M,AS=TO/K,SORT/S,VISIBLE/S,TABS/S,EOL/S"
  95. #define OPT_FROM    0
  96. #define OPT_TO      1
  97. #define OPT_SORT    2
  98. #define OPT_VISIBLE 3
  99. #define OPT_TABS    4
  100. #define OPT_EOL     5
  101.  
  102. #define CONCATBUFSIZE 102400L
  103.  
  104. typedef struct Global {
  105.   struct DosLibrary *DOSBase;
  106.   struct Library *UtilityBase;
  107.   struct List *list;
  108.   BPTR output;
  109.   BOOL visible;
  110.   BOOL tabs;
  111.   BOOL eol;
  112.   LONG (*concat)(UBYTE *filename, struct Global *global);
  113.   UBYTE *buffer;
  114.   LONG  bufsize;
  115. } Global;
  116.  
  117. typedef struct {
  118.   struct Node nn_Node;
  119.   UBYTE nn_filename[MAXNAMELEN+1];
  120. } NameNode;
  121.  
  122.  
  123. LONG initlist(Global *global);
  124. VOID freelist(Global *global);
  125. LONG insert(UBYTE *filename, Global *global);
  126. LONG concatall(Global *global);
  127. LONG concat(UBYTE *filename, Global *global);
  128. LONG fastcat(UBYTE *filename, Global *global);
  129.  
  130. APTR allocBufferVec(LONG *bufsize, Global *global);
  131.  
  132. char const versionID[] = VERSTAG;
  133. char const copyright[] = "$COPYRIGHT:©1992,1993 Torsten Poulin$";
  134.  
  135.  
  136. LONG entrypoint(VOID)
  137. {
  138.   struct DosLibrary *DOSBase;
  139.   struct RDArgs *args;
  140.   Global *global;
  141.   LONG arg[6];
  142.   LONG rc = RETURN_OK;
  143.  
  144.   if (!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
  145.     return RETURN_FAIL;
  146.  
  147.   if (!(global = AllocVec(sizeof(Global), MEMF_CLEAR)))
  148.   {
  149.     PrintFault(ERROR_NO_FREE_STORE, PROGNAME);
  150.     rc = RETURN_FAIL;
  151.   }
  152.   else
  153.   {
  154.     global->DOSBase = DOSBase;
  155.     if (!(global->UtilityBase = OpenLibrary("utility.library", 37L)))
  156.       rc = RETURN_FAIL;
  157.     else
  158.     {
  159.       arg[OPT_FROM] = arg[OPT_TO] = arg[OPT_SORT] =
  160.     arg[OPT_VISIBLE] = arg[OPT_TABS] = arg[OPT_EOL] = 0L;
  161.  
  162.       if (!(args = ReadArgs(TEMPLATE, arg, NULL)))
  163.       {
  164.     printerror(PROGNAME, global);
  165.     rc = RETURN_ERROR;
  166.       }
  167.       else
  168.       {
  169.     global->visible = (BOOL) arg[OPT_VISIBLE];
  170.     global->tabs = (BOOL) arg[OPT_TABS];
  171.     global->eol = (BOOL) arg[OPT_EOL];
  172.  
  173.     if (!arg[OPT_TO])
  174.       global->output = Output();
  175.     else if (!(global->output = Open((UBYTE *) arg[OPT_TO],
  176.                      MODE_NEWFILE)))
  177.     {
  178.       PutStr("Cannot open ");
  179.       PutStr((UBYTE *) arg[OPT_TO]);
  180.       PutStr("\n");
  181.       rc = RETURN_ERROR;
  182.     }
  183.  
  184.     if (global->output)
  185.     {
  186.       global->concat = concat;
  187.       if (!global->visible && !global->eol && !global->tabs &&
  188.           !IsInteractive(global->output))
  189.       {
  190.         /* If we can't get the buffer, we simply use the slower
  191.          * method.
  192.          */
  193.         global->bufsize = CONCATBUFSIZE;
  194.         if (global->buffer = allocBufferVec(&global->bufsize, global))
  195.           global->concat = fastcat;
  196.       }
  197.  
  198.       if (!arg[OPT_FROM])
  199.         rc = global->concat(NULL, global);
  200.       else if (!arg[OPT_SORT])
  201.         rc = foreach((UBYTE **) arg[OPT_FROM], global->concat, global);
  202.       else if ((rc = initlist(global)) != ERROR_NO_FREE_STORE)
  203.       {
  204.         if (!(rc = foreach((UBYTE **) arg[OPT_FROM], insert, global)))
  205.           rc = concatall(global);
  206.         freelist(global);
  207.       }
  208.       if (arg[OPT_TO])
  209.         Close(global->output);
  210.       if (global->buffer)
  211.         FreeVec(global->buffer);
  212.     }
  213.  
  214.     FreeArgs(args);
  215.  
  216.     if (rc == ERROR_BREAK)
  217.     {
  218.       PrintFault(ERROR_BREAK, NULL);
  219.       rc = RETURN_WARN;
  220.     }
  221.     else if (rc == ERROR_NO_FREE_STORE)
  222.     {
  223.       PrintFault(ERROR_NO_FREE_STORE, PROGNAME);
  224.       rc = RETURN_FAIL;
  225.     }
  226.     else if (rc != RETURN_OK)
  227.       printerror(PROGNAME, global);
  228.       }
  229.       CloseLibrary(global->UtilityBase);
  230.     }
  231.     FreeVec(global);
  232.   }
  233.   CloseLibrary((struct Library *) DOSBase);
  234.   return rc;
  235. }
  236.  
  237.  
  238. LONG initlist(Global *global)
  239. {
  240.   if (!(global->list = AllocVec(sizeof(struct List), MEMF_CLEAR)))
  241.     return ERROR_NO_FREE_STORE;
  242.   /* Initialize list header */
  243.   global->list->lh_Head = (struct Node *) &global->list->lh_Tail;
  244.   global->list->lh_Tail = 0;
  245.   global->list->lh_TailPred = (struct Node *) &global->list->lh_Head;
  246.   return RETURN_OK;
  247. }
  248.  
  249.  
  250. VOID freelist(Global *global)
  251. {
  252.   NameNode *worknode;
  253.   NameNode *nextnode;
  254.  
  255.   worknode = (NameNode *) (global->list->lh_Head);
  256.   while (nextnode = (NameNode *) (worknode->nn_Node.ln_Succ))
  257.   {
  258.     FreeVec(worknode);
  259.     worknode = nextnode;
  260.   }
  261.   FreeVec(global->list);
  262. }
  263.  
  264.  
  265. LONG insert(UBYTE *filename, Global *global)
  266. {
  267.   struct Library *UtilityBase = global->UtilityBase;
  268.   NameNode *namenode;
  269.   struct Node *node;
  270.  
  271.   if (!(namenode = AllocVec(sizeof(NameNode), MEMF_CLEAR)))
  272.     return ERROR_NO_FREE_STORE;
  273.   else
  274.   {
  275.     strcpy(namenode->nn_filename, filename);
  276.     namenode->nn_Node.ln_Name = namenode->nn_filename;
  277.  
  278.     if (global->list->lh_TailPred == (struct Node *) global->list)
  279.       AddHead(global->list, (struct Node *) namenode);
  280.     else
  281.     {
  282.       for (node=global->list->lh_Head; node->ln_Succ; node=node->ln_Succ)
  283.     if (Stricmp(node->ln_Name, filename) >= 0)
  284.       break;
  285.       if (node->ln_Succ)
  286.     Insert(global->list, (struct Node *) namenode, node->ln_Pred);
  287.       else
  288.     AddTail(global->list, (struct Node *) namenode);
  289.     }
  290.  
  291.     return RETURN_OK;
  292.   }
  293. }
  294.  
  295.  
  296. LONG concatall(Global *global)
  297. {
  298.   struct Node *node;
  299.   LONG rc = RETURN_OK;
  300.  
  301.   if (global->list->lh_TailPred != (struct Node *) global->list)
  302.     for (node = global->list->lh_Head; node->ln_Succ; node = node->ln_Succ)
  303.       if ((rc = global->concat(node->ln_Name, global)) == ERROR_BREAK)
  304.     break;
  305.   return rc;
  306. }
  307.  
  308.  
  309. LONG concat(UBYTE *filename, Global *global)
  310. {
  311.   struct DosLibrary *DOSBase = global->DOSBase;
  312.   register UBYTE breakcheck = 0;
  313.   BPTR input;
  314.   LONG c;
  315.  
  316.   if (!filename)
  317.     input = Input();
  318.   else if (!(input = Open(filename, MODE_OLDFILE)))
  319.   {
  320.     PutStr("Cannot open ");
  321.     printerror(filename, global);
  322.     return RETURN_WARN;
  323.   }
  324.  
  325.   while ((c = FGetC(input)) != -1)
  326.   {
  327.     if (global->visible)
  328.     {
  329.       if (global->eol && c == '\n')
  330.     FPutC(global->output, '$');
  331.       else if (global->tabs && c == '\t')
  332.       {
  333.     FPutC(global->output, '^');
  334.     c = 'I';
  335.       }
  336.       else if (c >= 0x80)
  337.       {
  338.     FPutC(global->output, 'M');
  339.     FPutC(global->output, '-');
  340.     c &= 0x7f;
  341.       }
  342.       if ((c < ' ' && c != '\t' && c != '\n') || c == 0x7F)
  343.       {
  344.     FPutC(global->output, '^');
  345.     if (c == 0x7F)
  346.       c = '?';
  347.     else
  348.       c += 'A' - 1;
  349.       }
  350.     }
  351.     FPutC(global->output, c);
  352.     if (!(breakcheck -= 4) && CheckSignal(SIGBREAKF_CTRL_C))
  353.     {
  354.       if (filename)
  355.         Close(input);
  356.       return ERROR_BREAK;
  357.     }
  358.   }
  359.   if (filename)
  360.     Close(input);
  361.   return RETURN_OK;
  362. }
  363.  
  364.  
  365. LONG fastcat(UBYTE *filename, Global *global)
  366. {
  367.   struct DosLibrary *DOSBase = global->DOSBase;
  368.   BPTR input;
  369.   LONG count, actual;
  370.  
  371.   if (!filename)
  372.     input = Input();
  373.   else if (!(input = Open(filename, MODE_OLDFILE)))
  374.   {
  375.     PutStr("Cannot open ");
  376.     printerror(filename, global);
  377.     return RETURN_WARN;
  378.   }
  379.  
  380.   count = 1;
  381.   while ((actual = Read(input,global->buffer,global->bufsize))>0 && count>0)
  382.   {
  383.     count = Write(global->output, global->buffer, actual);
  384.  
  385.     if (CheckSignal(SIGBREAKF_CTRL_C))
  386.     {
  387.       if (filename)
  388.         Close(input);
  389.       return ERROR_BREAK;
  390.     }
  391.   }
  392.   if (filename)
  393.     Close(input);
  394.   return RETURN_OK;
  395. }
  396.  
  397.  
  398. APTR allocBufferVec(LONG *bufsize, Global *global)
  399. {
  400.   APTR buffer;
  401.  
  402.   for (; *bufsize > 256L; *bufsize /= 2)
  403.     if (buffer = AllocVec(*bufsize, MEMF_CLEAR))
  404.       return buffer;
  405.   return NULL;
  406. }
  407.